package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.constant.ErrorConstantCode;
import cn.itsource.ymcc.constant.RedisConstants;
import cn.itsource.ymcc.domain.CourseType;
import cn.itsource.ymcc.mapper.CourseTypeMapper;
import cn.itsource.ymcc.service.ICourseTypeService;
import cn.itsource.ymcc.util.AssertUtil;
import cn.itsource.ymcc.vo.CrumbsTypeVo;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程目录 服务实现类
 * </p>
 *
 * @author gwk
 * @since 2023-02-24
 */
@Service
@Slf4j
public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {


    // 本地缓存
    private Map<String, List<CourseType>> chache = new HashMap<>();

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;


    /**
     * 课程分类树
     *
     * @return
     */
    @Override
    @Cacheable(cacheNames = RedisConstants.COURSE_TYPE_KEY,key = "'all'")
    public List<CourseType> treeData() {
        log.info("返回的是缓存中的数据！！！");
        //到数据库查询
        return getlistTree();
    }

    /**
     * 新增课程分类下课程数量
     * @param courseTypeId
     */
    @Override
    public void addTotalCount(Long courseTypeId) {
        baseMapper.addTotalCount(courseTypeId);
    }

    /**
     * 查询面包屑
     * @param TypeId
     * @return
     */
    @Override
    public List<CrumbsTypeVo> getCrumbs(Long TypeId) {
        // 1. 参数校验，分类id 不能为空
        AssertUtil.isNotNull(TypeId, ErrorConstantCode.COURSE_TYPE_ID_NULL_30040);
        // 2. 根据 分类id 查询对应的path
        CourseType courseType = selectById(TypeId);
        AssertUtil.isNotNull(courseType,ErrorConstantCode.COURSE_TYPE_NULL_30050);
        String path = courseType.getPath();

        // 3. path 校验， path 拆分 得到[顶级，二级，三级 ...]
        List<CrumbsTypeVo> crumbs = new ArrayList<>();
        if(StringUtils.isNotBlank(path)){
            String[] split = path.split("\\."); // 字符串拆分，有可能需要做字符转义
            log.info("拆分得到的数组：{}", Arrays.toString(split));

            // 4. 循环查询 分类的信息 和 兄弟分类的数据 -- 存放到List
            for (String sid : split) {
                CrumbsTypeVo crumbsTypeVo = new CrumbsTypeVo();
                CourseType type = selectById(sid);
                crumbsTypeVo.setOwnerProductType(type);

                // 查兄弟 ，拥有相同pid
                Wrapper<CourseType> warpper = new EntityWrapper<>();
                warpper.eq("pid", type.getPid());
                List<CourseType> courseTypes = selectList(warpper);

                crumbsTypeVo.setOtherProductTypes(courseTypes);

                crumbs.add(crumbsTypeVo);
            }
        }

        return crumbs;
    }


    /**
     * 课程分类树
     *
     * @return
     */

    public List<CourseType> treeDataForRedis() {

        // 先去缓存存中查询
        Object result = redisTemplate.opsForValue().get(RedisConstants.COURSE_TYPE_KEY);
        if (result != null) {
            log.info("返回的是缓存中的数据！！！");
            return (List<CourseType>) result;
        } else {
            //到数据库查询
            return getlistTree();
        }
    }

    /**
     * 课程分类树
     *
     * @return
     */
    public List<CourseType> treeDataForLocal() {

        // 先去缓存存中查询
        List<CourseType> courseTypes = chache.get(RedisConstants.COURSE_TYPE_KEY);
        if (courseTypes != null) {
            return courseTypes;
        } else {
            //到数据库查询
            return getlistTree();
        }
    }


    private List<CourseType> getlistTree() {
        // 1. 先把所有的分类都查询出来
        List<CourseType> allType = selectList(null);

        // 1.2 把所有的分类，转换到Map中，方便查找上级
        Map<Long, CourseType> map = allType.stream().collect(Collectors.toMap(CourseType::getId, t -> t));


//        for (CourseType courseType : allType) {
//            map.put(courseType.getId(),courseType);
//        }

        List<CourseType> first = new ArrayList<>();

        allType.forEach(courseType -> {
            // 2. 把一级分类从所有中找出来，封装到集合中，最终返回一级分类
            if (courseType.getPid() == null || courseType.getPid().equals(0L)) {
                first.add(courseType);
            } else {
                // 3. 其他的分类，自己找到自己的上级分类（通过pid,到map中查找上级），
                CourseType parent = map.get(courseType.getPid());
                if (parent != null) {
                    // 3.2 再把自己，放到上级分类的 children 中
                    parent.getChildren().add(courseType);
                }
            }
        });

//        for (CourseType courseType : allType) {
//            // 2. 把一级分类从所有中找出来，封装到集合中，最终返回一级分类
//            if(courseType.getPid()==null || courseType.getPid().equals(0L)){
//                first.add(courseType);
//            }else {
//                // 3. 其他的分类，自己找到自己的上级分类（通过pid,到map中查找上级），
//                CourseType parent = map.get(courseType.getPid());
//                if(parent!=null){
//                    // 3.2 再把自己，放到上级分类的 children 中
//                    parent.getChildren().add(courseType);
//                }
//            }
//        }

        log.info("到数据库查询，添加到缓存中");
        //chache.put(RedisConstants.COURSE_TYPE_KEY,first);
        //redisTemplate.opsForValue().set(RedisConstants.COURSE_TYPE_KEY, first);
        // 4. 返回一级分类集合
        return first;
    }

    @Override
    @CacheEvict(cacheNames = RedisConstants.COURSE_TYPE_KEY,key = "'all'")
    public boolean insert(CourseType entity) {
        //redisTemplate.delete(RedisConstants.COURSE_TYPE_KEY);
        boolean insert = super.insert(entity);
        return insert;
    }

    @Override
    @CacheEvict(cacheNames = RedisConstants.COURSE_TYPE_KEY,key = "'all'")
    public boolean deleteById(Serializable id) {
        //redisTemplate.delete(RedisConstants.COURSE_TYPE_KEY);
        boolean deleteById = super.deleteById(id);
        return deleteById;
    }

    @Override
    @CacheEvict(cacheNames = RedisConstants.COURSE_TYPE_KEY,key = "'all'")
    public boolean updateById(CourseType entity) {
        //redisTemplate.delete(RedisConstants.COURSE_TYPE_KEY);
        boolean updateById = super.updateById(entity);
        return updateById;
    }
}
